﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TrenchcoatRobots.Datatypes;
using TrenchcoatRobots.Classes.ComponentClasses;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace TrenchcoatRobots.Classes.ComponentClasses.Colliders {
	/// <summary>
	/// ColliderManager is a public, static class with methods for colliding. This class is available in the entire project!
	/// </summary>
	class ColliderManager {

		public static void CollideObjects(BoxCollider first, BoxCollider second) {
			/*
				Originally had a smart solution using the dynamic keyword here, however I couldn't get it to work
				and had to code in the collision only as BoxColliders instead of allowing several different types
				of colliders.
			*/
			BoxCollider one = first;
			BoxCollider two = second;
			CollisionInfo collision = Collide(one, two);
			if (collision != null) {
				first.Parent().Collided(second.Parent(), collision);
			}
		}

		internal static CollisionInfo Collide(BoxCollider one, BoxCollider two) {
			try {
				Rectangle first = new Rectangle(
					(int)Math.Floor(one.Parent().Position.X + one.Offset.X),
					(int)Math.Floor(one.Parent().Position.Y + one.Offset.Y),
					(int)Math.Floor(one.Size.X),
					(int)Math.Floor(one.Size.Y)
					);
				Rectangle second = new Rectangle(
					(int)Math.Floor(two.Parent().Position.X + two.Offset.X),
					(int)Math.Floor(two.Parent().Position.Y + two.Offset.Y),
					(int)Math.Floor(two.Size.X),
					(int)Math.Floor(two.Size.Y)
					);
				#region Point
				if (second.Width == 0 && second.Height == 0) {
					if (first.Contains(second.Location)) {
						Vector2 norm = new Vector2();

						//SLIGHT CASE OF THE DRAGONS

						int leftDist = first.Left - second.Location.X;
						int rightDist = first.Right - second.Location.X;
						int topDist = first.Top - second.Location.Y;
						int bottomDist = first.Bottom - second.Location.Y;

						if (leftDist > rightDist && leftDist > topDist && leftDist > bottomDist) {
							norm = new Vector2(-1, 0);
						}
						if (rightDist > leftDist && rightDist > topDist && rightDist > bottomDist) {
							norm = new Vector2(1, 0);
						}
						if (topDist > rightDist && topDist > leftDist && topDist > bottomDist) {
							norm = new Vector2(0, -1);
						}
						if (bottomDist > rightDist && bottomDist > leftDist && bottomDist > topDist) {
							norm = new Vector2(0, 1);
						}

						//ABSOLUTELY DRAGONS

						return new CollisionInfo(norm, new Vector2(second.Location.X, second.Location.Y));
					}
				}
				#endregion
				else {

					Vector2 pos = new Vector2();
					Vector2 norm = new Vector2();
					if (second.Intersects(first)) {
						#region Here be dragons

						int leftDist = first.Left - second.Left;
						int rightDist = first.Right - second.Right;
						int topDist = first.Top - second.Top;
						int bottomDist = first.Bottom - second.Bottom;

						if (leftDist > rightDist && leftDist > topDist && leftDist > bottomDist) {
							norm = new Vector2(-1, 0);
						}
						if (rightDist > leftDist && rightDist > topDist && rightDist > bottomDist) {
							norm = new Vector2(1, 0);
						}
						if (topDist > rightDist && topDist > leftDist && topDist > bottomDist) {
							norm = new Vector2(0, -1);
						}
						if (bottomDist > rightDist && bottomDist > leftDist && bottomDist > topDist) {
							norm = new Vector2(0, 1);
						}

						int width = 0;
						if (first.Right - second.Left > 0) {
							width = first.Right - second.Left;
						}
						else {
							width = second.Left - first.Right;
						}

						int height = 0;
						if (first.Top - second.Bottom > 0) {
							height = first.Top - second.Bottom;
						}
						else {
							height = second.Bottom - first.Top;
						}

						int xPos = 0;
						if (second.Left > first.Left) {
							xPos = first.Left;
						}
						else {
							xPos = second.Left;
						}

						int yPos = 0;
						if (second.Top > first.Top) {
							yPos = first.Top;
						}
						else {
							yPos = second.Top;
						}

						Rectangle merged = new Rectangle(xPos, yPos, width, height);

						pos = new Vector2(merged.Center.X, merged.Center.Y);

						#endregion

						return new CollisionInfo(norm, pos);
					}
				}


				return null;
			} catch (NullReferenceException err){
				return null;
			}
		}

		internal static CollisionInfo Collide(CircleCollider one, BoxCollider two) {
			Vector2 center = one.Parent().Position + one.Offset;

			Vector2[] points = {
								new Vector2(two.LeftEdge(),two.TopEdge()),
								new Vector2(two.RightEdge(),two.TopEdge()),
								new Vector2(two.RightEdge(),two.BottomEdge()),
								new Vector2(two.LeftEdge(),two.BottomEdge())
							 };

			for (int i = 0; i < 4; i++) {
				if ((points[i] - center).LengthSquared() < Math.Pow(one.Radius, 2)) {
					Vector2 normal = center - points[i];
					normal.Normalize();
					return new CollisionInfo(
							normal,
							one.Parent().Position + (-normal * one.Radius)
						);
				}
			}

			if (two.LeftEdge() + one.Radius < center.X && two.RightEdge() + one.Radius > center.X) {
				if (two.TopEdge() + one.Radius < center.Y && two.BottomEdge() + one.Radius > center.Y) {
					Vector2 normal = center - (two.Parent().Position + two.Offset);
					normal.Normalize();

					return new CollisionInfo(normal, one.Parent().Position + (-normal * one.Radius));
				}
			}


			return null;
		}
		internal static CollisionInfo Collide(BoxCollider one, CircleCollider two) {
			return Collide(two, one);
		}
		internal static CollisionInfo Collide(CircleCollider one, CircleCollider two) {
			if (Math.Pow(one.Radius + two.Radius, 2) > (one.Parent().Position - two.Parent().Position).LengthSquared()) {
				Vector2 normal = (two.Parent().Position + two.Offset) - (one.Parent().Position + one.Offset);
				normal.Normalize();
				return new CollisionInfo(normal, one.Parent().Position + (normal * one.Radius));
			}
			return null;
		}
	}
}
